package com.admin_system.service.impl;

import com.admin_system.service.VerificationCodeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.security.SecureRandom;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 验证码服务实现类
 * 使用内存存储验证码和重置令牌
 * 注意：在生产环境中，应当使用数据库或缓存来存储验证码和令牌
 */
@Service
public class VerificationCodeServiceImpl implements VerificationCodeService {

    private static final Logger logger = LoggerFactory.getLogger(VerificationCodeServiceImpl.class);
    
    // 验证码长度
    @Value("${app.verification.code.length:6}")
    private int codeLength;
    
    // 验证码有效期（毫秒）
    @Value("${app.verification.code.expiry:600000}")
    private long codeExpiry;
    
    // 重置令牌有效期（毫秒）
    @Value("${app.verification.reset.expiry:1800000}")
    private long resetExpiry;
    
    // 存储验证码的Map
    private final Map<String, VerificationCodeInfo> verificationCodes = new ConcurrentHashMap<>();
    
    // 存储重置令牌的Map
    private final Map<String, ResetTokenInfo> resetTokens = new ConcurrentHashMap<>();
    
    /**
     * 生成验证码并保存
     * 
     * @param email 关联的邮箱
     * @return 生成的验证码
     */
    @Override
    public String generateCode(String email) {
        // 生成6位数字验证码
        String code = generateRandomCode(codeLength);
        
        // 保存验证码和过期时间
        long expiryTime = System.currentTimeMillis() + codeExpiry;
        verificationCodes.put(email, new VerificationCodeInfo(code, expiryTime));
        
        logger.info("为邮箱 {} 生成验证码", email);
        return code;
    }
    
    /**
     * 验证验证码是否有效
     * 
     * @param email 关联的邮箱
     * @param code 要验证的验证码
     * @return 验证通过返回true，失败返回false
     */
    @Override
    public boolean verifyCode(String email, String code) {
        VerificationCodeInfo codeInfo = verificationCodes.get(email);
        
        if (codeInfo == null) {
            logger.warn("邮箱 {} 没有找到验证码", email);
            return false;
        }
        
        // 检查验证码是否过期
        if (codeInfo.isExpired()) {
            logger.warn("邮箱 {} 的验证码已过期", email);
            verificationCodes.remove(email);
            return false;
        }
        
        // 检查验证码是否匹配
        boolean isValid = codeInfo.getCode().equals(code);
        
        if (isValid) {
            logger.info("邮箱 {} 的验证码验证成功", email);
            // 验证成功后删除验证码
            verificationCodes.remove(email);
        } else {
            logger.warn("邮箱 {} 的验证码验证失败", email);
        }
        
        return isValid;
    }
    
    /**
     * 创建密码重置令牌
     * 
     * @param email 关联的邮箱
     * @return 重置令牌
     */
    @Override
    public String createResetToken(String email) {
        // 生成随机令牌
        String token = UUID.randomUUID().toString();
        
        // 保存令牌和过期时间
        long expiryTime = System.currentTimeMillis() + resetExpiry;
        resetTokens.put(email, new ResetTokenInfo(token, expiryTime));
        
        logger.info("为邮箱 {} 创建重置令牌", email);
        return token;
    }
    
    /**
     * 检查是否存在有效的重置令牌
     * 
     * @param email 关联的邮箱
     * @return 存在有效的重置令牌返回true，否则返回false
     */
    @Override
    public boolean hasValidResetToken(String email) {
        ResetTokenInfo tokenInfo = resetTokens.get(email);
        
        if (tokenInfo == null) {
            logger.warn("邮箱 {} 没有找到重置令牌", email);
            return false;
        }
        
        // 检查令牌是否过期
        if (tokenInfo.isExpired()) {
            logger.warn("邮箱 {} 的重置令牌已过期", email);
            resetTokens.remove(email);
            return false;
        }
        
        return true;
    }
    
    /**
     * 清除重置令牌
     * 
     * @param email 关联的邮箱
     */
    @Override
    public void clearResetToken(String email) {
        resetTokens.remove(email);
        logger.info("清除邮箱 {} 的重置令牌", email);
    }
    
    /**
     * 生成随机验证码
     * 
     * @param length 验证码长度
     * @return 随机验证码
     */
    private String generateRandomCode(int length) {
        SecureRandom random = new SecureRandom();
        StringBuilder sb = new StringBuilder(length);
        
        for (int i = 0; i < length; i++) {
            sb.append(random.nextInt(10));
        }
        
        return sb.toString();
    }
    
    /**
     * 验证码信息内部类
     */
    private static class VerificationCodeInfo {
        private final String code;
        private final long expiryTime;
        
        public VerificationCodeInfo(String code, long expiryTime) {
            this.code = code;
            this.expiryTime = expiryTime;
        }
        
        public String getCode() {
            return code;
        }
        
        public boolean isExpired() {
            return System.currentTimeMillis() > expiryTime;
        }
    }
    
    /**
     * 重置令牌信息内部类
     */
    private static class ResetTokenInfo {
        private final String token;
        private final long expiryTime;
        
        public ResetTokenInfo(String token, long expiryTime) {
            this.token = token;
            this.expiryTime = expiryTime;
        }
        
        public String getToken() {
            return token;
        }
        
        public boolean isExpired() {
            return System.currentTimeMillis() > expiryTime;
        }
    }
} 